<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>


<script>
  /*
  * 值类型、简单类型、基本类型:
  * string，number，boolean，null，undefined
  *
  * 引用类型、复杂类型:
  * object、array、function
  * */

  // Math
  // Date
  // Object
  // 构造函数
  // 实例 = new Object()

  // []
  // {}
  // typeof [] // object
  // typeof {} // object
  // Array.isArray([])
  // ({}) instanceof Array
  // 实例 instanceof 构造函数

  // let arr = []
  // arr.aaa = 123
  // console.log(arr.aaa)

  // const f1 = () => alert(123)
  // f1.testProp = 'hahha'
  // console.log(f1.testProp)

  // 对象是通过函数创建的
  // 函数又是一种对象

  // 首字母小写开头的方法一般是普通函数
  // 首字母*大写*开头的方法一般是构造函数
  // new Array()

  // 面向对象编程
  function Car(name, color) {
    // console.log(this)
    this.name = name
    this.color = color
  } // 函数 prototype => 原型
  // console.log(Car)
  // console.log(Car.prototype)
  Car.prototype.price = '￥34000.00'
  Car.prototype.sayHello = function () {
    alert('hello 奔驰')
  }
  let b = new Car('宝马', '#fff'); // 实例 __proto__ => 隐式原型

  // console.log('============')
  // console.log(b)
  // console.log(b.price)
  // console.log(b.hasOwnProperty('price'))
  // console.log(b.hasOwnProperty('name'))


  // 继承 是通过*原型*链体现的

  // console.log(b instanceof Car)
  // b.__proto__ === Car.prototype

  // console.log([] instanceof Array)
  //
  // console.log(Car.prototype === b.__proto__)
  // console.log(Car.prototype.constructor)
  // 构造函数.prototype.constructor 指向该函数的本身
  // console.log(b.__proto__)

  // let num = new Number(123)
  // console.log(num.toFixed(10))



  // ===================

  // console.log(count)
  // count = 100
  // console.log(count)
  // var count

  // eval('console.log(123)')

  let count = 0
  function f(x, y, z, w) {
    // console.log(this)
    count += 1
    console.log(count)
    console.log(arguments)
  }
  // f(1, 10, 99, 'aaa')
  // f(1, 10, 99)

  // ES5 谁调用这个方法谁就是this
  // 箭头函数，在哪定义谁就是this

  function f1() {
    console.log(this)
    console.log(this.x)
  }
  // .bind() 返回一个新函数，
  // 无论什么形式调用，始终是bind绑定的this
  /*
  let f2 = f1.bind({
    x: '我是bind绑定的this.x'
  })
  f2.call({
    x: '我是call绑定的this.x'
  })
  // f2()

  // f1()

  f1.call({
    x: '我是call绑定的this.x'
  })

  f1.apply({
    x: '我是apply绑定的this.x'
  })*/

  /*
  let obj = {
    x: 10,
    fn: function () {
      // console.log(this)
      // console.log(this.x)
      function f() {
        console.log(this)
        console.log(this.x)
      }
      f()
    }
  }
  obj.fn()
  */

  let obj = {
    x: 10,
    fn() {
      const f = () => {
        console.log(this)
        console.log(this.x)
      }
      /*function f() {
        console.log(this)
        console.log(this.x)
      }*/
      f()
    }
  }
  // obj.fn()

  // java
  // c

  // 闭包：跨作用域访问变量
  // 1. 函数嵌套
  // 2. 内部函数引用了外部函数的数据

  // 缺点：导致内存泄露

  /*function f2() {
    let x =10
    function f2() {
      console.log(x)
    }
  }*/

  function fn() {
    let max = 0
    function bar() {
      max += 1
      console.log(max)
    }
    return bar
  }

  let ff = fn();
  // ff() // 1
  // ff() // 2
  // ff() // 3

  // console.log(ff()) // 1
  // console.log(ff()) // 1


  ;(function f2() {
    for (var i = 0; i < 10; i++) {
      // console.log(i)
    }
    // i = null
    // console.log('()()', i)
  })()

  // f2()

  // 语法糖

  // ES6 class
  class Person {
    constructor(name, age) {
      this.name = name
      this.age = age
    }

    sayHi() {
      alert('hi')
    }
  }
  // module

  // var let const function class import



  Person.prototype.color = 'red'

  let zhangsan = new Person('张三', 18)
  console.log(zhangsan)
  console.log(zhangsan.__proto__)

  // console.log(Person.prototype.constructor)



</script>
</body>
</html>